package com.fushenlan.epidemicControl.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fushenlan.Vo.AppUserVo;
import com.fushenlan.Vo.CertificateInfoVo;
import com.fushenlan.dto.NeighborhoodMemberDTO;
import com.fushenlan.epidemicControl.dto.AddOrUpdateUserReqDTO;
import com.fushenlan.epidemicControl.dto.QueryUserReqDTo;
import com.fushenlan.epidemicControl.mapper.NeighborhoodInfoMapper;
import com.fushenlan.epidemicControl.mapper.NeighborhoodMemberMapper;
import com.fushenlan.epidemicControl.mapper.UserMapper;
import com.fushenlan.epidemicControl.service.UserService;
import com.fushenlan.po.InhabitantInfoDO;
import com.fushenlan.po.NeighborhoodMemberDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author PC
 * @title: UserService
 * @projectName SpringBootDemo
 * @description: TODO
 * @date 2021/8/14 18:43
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private NeighborhoodMemberMapper neighborhoodMemberMapper;

    @Autowired
    private NeighborhoodInfoMapper neighborhoodInfoMapper;

    /**
     * 插入
     *
     * @param appUserVo
     */
    @Override
    @Transactional
    public Map<String, Object> insert(AppUserVo appUserVo) {
        HashMap<String, Object> map = new HashMap<>();
        CertificateInfoVo myInfo = appUserVo.getMyInfo();
        //验证是否已经注册
        InhabitantInfoDO infoDO = userMapper.selectByIdentity(myInfo.getIdentifyType(), myInfo.getIdentifyNo());
        if (infoDO != null && 1 == infoDO.getRegistered()) {
            String phoneNumber = infoDO.getPhoneNumber();
            int length = phoneNumber.length();
            throw new RuntimeException("证件已注册，请使用手机尾号" + phoneNumber.substring(length - 4, length) + "的微信登录");
        }
        //解析thirdSession

        String createTime = DateUtil.now();
        //插入用户，并标记来源
        List<CertificateInfoVo> familyList = appUserVo.getFamilyList();
        if (infoDO == null) {
            //因为后台的居委会成员需要手动插入，默认在居民表中也插入了一条数据，是居委会成员的同时他也是居民
            InhabitantInfoDO inhabitantInfoDO = new InhabitantInfoDO();
            inhabitantInfoDO.setFamilyId(0L);
            inhabitantInfoDO.setStreetCode(appUserVo.getStreetCode());
            inhabitantInfoDO.setNeighborhoodId(appUserVo.getNeighborhoodId());
            inhabitantInfoDO.setResidentialId(appUserVo.getResidentialId());
            inhabitantInfoDO.setBuildingId(appUserVo.getBuildingId());
            inhabitantInfoDO.setHouseId(appUserVo.getHouseId());
            inhabitantInfoDO.setRoleId(String.valueOf(appUserVo.getRoleId()));
            inhabitantInfoDO.setRelationId(1);

            inhabitantInfoDO.setUserName(myInfo.getUserName());
            inhabitantInfoDO.setIdentifyType(myInfo.getIdentifyType());
            inhabitantInfoDO.setIdentifyNo(myInfo.getIdentifyNo());
            inhabitantInfoDO.setPhoneNumber(myInfo.getPhoneNumber());
            // 1-app 2-pc
            inhabitantInfoDO.setSourceChannel(1);
            inhabitantInfoDO.setCreateDate(createTime);
            inhabitantInfoDO.setUpdateDate(createTime);
            inhabitantInfoDO.setOpenId(appUserVo.getOpenid());
            inhabitantInfoDO.setRegistered(1);
            userMapper.insert(inhabitantInfoDO);
            insertFamily(appUserVo, createTime, inhabitantInfoDO.getId(), familyList);
            //返回居民信息到前端
            map.put("inhabitantInfo", inhabitantInfoDO);
            map.put("userId", inhabitantInfoDO.getId());
            map.put("userName", inhabitantInfoDO.getUserName());
            map.put("roleId", inhabitantInfoDO.getRoleId());
            queryNeighborhoodMember(map, inhabitantInfoDO.getId());
        } else {
            //更新用户，标记已注册
            infoDO.setRegistered(1);
            // 1-app 2-pc
            infoDO.setSourceChannel(1);
            infoDO.setUpdateDate(createTime);
            infoDO.setOpenId(appUserVo.getOpenid());
            userMapper.updateById(infoDO);
            //查询家庭成员
            QueryWrapper<InhabitantInfoDO> wrapper = new QueryWrapper<InhabitantInfoDO>();
            wrapper.ge("familyId", infoDO.getId());
            List<InhabitantInfoDO> list = userMapper.selectList(wrapper);
            //对比前端录入的家庭成员名单，如果和后台有相同的证件，则不再录入，不同的继续添加
            if (CollUtil.isNotEmpty(list) && CollectionUtil.isNotEmpty(familyList)) {
                familyList = familyList.stream().filter(vo -> !list.stream().allMatch(db -> db.getIdentifyType().equals(vo.getIdentifyType())
                        && db.getIdentifyNo().equals(vo.getIdentifyNo())
                        && db.getUserName().equals(vo.getUserName()))).collect(Collectors.toList());
            }
            insertFamily(appUserVo, createTime, infoDO.getId(), familyList);
            //返回居民信息到前端
            map.put("inhabitantInfo", infoDO);
            map.put("roleId", infoDO.getRoleId());
            map.put("userId", infoDO.getId());
            map.put("userName", infoDO.getUserName());
            queryNeighborhoodMember(map, infoDO.getId());
        }
        return map;
    }

    /**
     * 需要查询下当前居民是不是居委会人员
     *
     * @param map
     * @param inhabitantId
     */
    private void queryNeighborhoodMember(Map<String, Object> map, Long inhabitantId) {
        //需要查询下当前居民是不是居委会人员，如果是居委会人员，返回居委会组织信息
        QueryWrapper<NeighborhoodMemberDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("inhabitantId", inhabitantId);
        NeighborhoodMemberDO memberDO = neighborhoodMemberMapper.selectOne(queryWrapper);
        if (memberDO == null) {
            //居民不可以跳转居委
            map.put("switchRole", 2);
        } else {
            //居民可以跳转居委，返回成员信息
            Map<String, Object> hashMap = new HashMap<>();
            hashMap.put("neighborhoodMemberId", memberDO.getId());
            hashMap.put("memberName", memberDO.getMemberName());
            //电话号码脱敏处理
            String phone = memberDO.getMemberPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
            hashMap.put("memberPhone", phone);
            hashMap.put("jobName", memberDO.getJobName());
            hashMap.put("inhabitantId", memberDO.getInhabitantId());
            map.put("switchRole", 1);
            map.put("neighborhoodMemberInfo", hashMap);
        }
    }

    /**
     * 插入家庭成员
     *
     * @param appUserVo
     * @param createTime
     * @param id
     * @param familyList
     */
    private void insertFamily(AppUserVo appUserVo, String createTime, long id, List<CertificateInfoVo> familyList) {
        if (CollectionUtil.isNotEmpty(familyList)) {
            for (CertificateInfoVo certificateInfoVo : familyList) {
                InhabitantInfoDO inhabitantInfo = new InhabitantInfoDO();
                inhabitantInfo.setFamilyId(id);
                inhabitantInfo.setUserName(certificateInfoVo.getUserName());
                inhabitantInfo.setIdentifyType(certificateInfoVo.getIdentifyType());
                inhabitantInfo.setIdentifyNo(certificateInfoVo.getIdentifyNo());
                inhabitantInfo.setPhoneNumber(certificateInfoVo.getPhoneNumber());
                inhabitantInfo.setRoleId(String.valueOf(appUserVo.getRoleId()));
                inhabitantInfo.setRelationId(3);
                inhabitantInfo.setNeighborhoodId(appUserVo.getNeighborhoodId());
                inhabitantInfo.setStreetCode(appUserVo.getStreetCode());
                inhabitantInfo.setResidentialId(appUserVo.getResidentialId());
                inhabitantInfo.setBuildingId(appUserVo.getBuildingId());
                inhabitantInfo.setHouseId(appUserVo.getHouseId());
                inhabitantInfo.setRegistered(2);
                // 1-app 2-pc
                inhabitantInfo.setSourceChannel(1);
                inhabitantInfo.setCreateDate(createTime);
                inhabitantInfo.setUpdateDate(inhabitantInfo.getCreateDate());
                userMapper.insert(inhabitantInfo);
            }
        }
    }

    /**
     * 更新
     *
     * @param reqDTo
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> updateUser(AddOrUpdateUserReqDTO reqDTo) {
        Map<String, Object> map = new HashMap<>();
        //查询居民是否存在
        InhabitantInfoDO inhabitantInfoDO = userMapper.selectById(reqDTo.getInhabitantId());
        log.info("from db by primary key id:{}", JSONUtil.toJsonStr(inhabitantInfoDO));
        if (inhabitantInfoDO == null) {
            throw new RuntimeException("未查询到居民信息");
        }
        InhabitantInfoDO buildInfo = buildInfo(reqDTo, inhabitantInfoDO);

        /**
         * 如果根据主键id查询出来的居民的证件信息和传入的参数一致，说明是点击修改页面后并无修改别的信息；
         * 如果familyId=0，说明当前修改人是我自己，则不能把证件信息修改为自己家庭成员任何一个
         * 如果familyId！=0，说明修改的是家庭成员信息，家庭成员证件信息不能修改为我自己的信息
         * 如果不一致，说明有修改信息
         * 根据familyId查询出所有的家庭成员
         */
        if (!Objects.equals(reqDTo.getFamilyId(), inhabitantInfoDO.getFamilyId())) {
            log.info("该被修改人非同一家庭成员，入参修改人familyId:{};数据库中familyId:{}", reqDTo.getFamilyId(), inhabitantInfoDO.getFamilyId());
            throw new RuntimeException("该被修改人非同一家庭成员");
        }
        if (inhabitantInfoDO.getIdentifyType().equals(reqDTo.getIdentifyType()) && inhabitantInfoDO.getIdentifyNo().equals(reqDTo.getIdentifyNo())) {
            userMapper.updateById(buildInfo);
        } else {
            //查询出所有家庭成员
            QueryWrapper<InhabitantInfoDO> wrapper = new QueryWrapper<>();
            wrapper.eq("familyId", inhabitantInfoDO.getFamilyId());
            List<InhabitantInfoDO> familyList = userMapper.selectList(wrapper);
            log.info("db查询所有家庭成员：{}", JSONUtil.toJsonStr(familyList));
            if (CollUtil.isNotEmpty(familyList)) {
                //如果family=0,我自己修改
                if (reqDTo.getFamilyId() == 0) {
                    //不能将我的证件信息修改成家庭成员的
                    boolean allMatch = familyList.stream().anyMatch(info -> info.getIdentifyType().equals(reqDTo.getIdentifyType()) && info.getIdentifyNo().equals(reqDTo.getIdentifyNo()));
                    log.info("anyMatch family info :{}", allMatch);
                    if (allMatch) {
                        throw new RuntimeException("不能修改我自己的证件信息为家庭成员的");
                    }
                } else {
                    //不能让家庭成员证件信息修改为我的,根据familyId找到我自己的id（familyId=0）
                    Long familyId = familyList.get(0).getFamilyId();
                    InhabitantInfoDO selectById = userMapper.selectById(familyId);
                    log.info("根据familyId查询数据库 :{}", JSONUtil.toJsonStr(selectById));
                    if (selectById.getIdentifyType().equals(reqDTo.getIdentifyType()) && selectById.getIdentifyNo().equals(reqDTo.getIdentifyNo())) {
                        throw new RuntimeException("不能将家庭成员信息修改为我自己的");
                    }
                }
            }
            userMapper.updateById(buildInfo);
        }
        map.put("userInfo", buildInfo);
        return map;
    }

    private InhabitantInfoDO buildInfo(AddOrUpdateUserReqDTO reqDTo, InhabitantInfoDO inhabitantInfoDO) {
        //组装信息
        inhabitantInfoDO.setUpdateDate(DateUtil.now());
        inhabitantInfoDO.setStreetCode(reqDTo.getStreetCode());
        inhabitantInfoDO.setNeighborhoodId(reqDTo.getNeighborhoodId());
        inhabitantInfoDO.setResidentialId(reqDTo.getResidentialId());
        inhabitantInfoDO.setBuildingId(reqDTo.getBuildingId());
        inhabitantInfoDO.setHouseId(reqDTo.getHouseId());
        inhabitantInfoDO.setUserName(reqDTo.getUserName());
        inhabitantInfoDO.setIdentifyType(reqDTo.getIdentifyType());
        inhabitantInfoDO.setIdentifyNo(reqDTo.getIdentifyNo());
        inhabitantInfoDO.setPhoneNumber(reqDTo.getPhoneNumber());
        return inhabitantInfoDO;
    }

    /**
     * 根据手机号查询居委会成员
     *
     * @param phoneNumber 居委人员手机
     * @return
     */
    @Override
    public Map<String, Object> selectNeighborhood(String phoneNumber) {
        return neighborhoodMemberMapper.selectMember(phoneNumber);
    }

    /**
     * 查询我的所有信息
     *
     * @param reqDTo
     * @return
     */
    @Override
    public Map<String, Object> selectAllById(QueryUserReqDTo reqDTo) {
        Map<String, Object> map = new HashMap<>();
        //查询居民信息
        List<Map<String, Object>> list = userMapper.selectAllById(reqDTo);
        log.info("db查询居民所有信息结果：{}", JSONUtil.toJsonStr(list));
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        //查询居委会信息
        Map<String, Object> neighborhoodMap = neighborhoodInfoMapper.selectByInhabitantId(reqDTo.getInhabitantId());
        log.info("db查询居委信息结果：{}", JSONUtil.toJsonStr(neighborhoodMap));
        map.put("neighborhoodInfo", neighborhoodMap);
        //过滤出家庭成员
        List<Map<String, Object>> familyList = list.stream().peek(m -> {
            if (m.get("id").equals(reqDTo.getInhabitantId())) {
                map.putAll(m);
            }
        }).filter(mp -> Integer.parseInt(mp.get("familyId").toString()) != 0 && reqDTo.getInhabitantId().equals(mp.get("familyId"))).collect(Collectors.toList());
        //获取出我自己的信息
        map.put("familyList", familyList);
        queryNeighborhoodMember(map, reqDTo.getInhabitantId());
        return map;
    }

    /**
     * 添加家庭成员
     *
     * @param reqDTo
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> addUser(AddOrUpdateUserReqDTO reqDTo) {
        //先验证下当前居民是否存在该家庭成员
        QueryWrapper<InhabitantInfoDO> wrapper = new QueryWrapper<>();
        wrapper.eq("familyId", reqDTo.getInhabitantId()).eq("identifyType", reqDTo.getIdentifyType()).eq("identifyNo", reqDTo.getIdentifyNo());
        List<InhabitantInfoDO> infoDOList = userMapper.selectList(wrapper);
        log.info("db查询家庭成员是否存在：{}", JSONUtil.toJsonStr(infoDOList));
        if (CollUtil.isNotEmpty(infoDOList)) {
            throw new RuntimeException("该证件号【" + reqDTo.getIdentifyNo() + "】居民已添加为家庭成员");
        }
        wrapper.clear();
        wrapper.eq("id", reqDTo.getInhabitantId()).eq("identifyType", reqDTo.getIdentifyType()).eq("identifyNo", reqDTo.getIdentifyNo());
        List<InhabitantInfoDO> infoDOListOfMine = userMapper.selectList(wrapper);
        log.info("db查询我自己是否存在：{}", JSONUtil.toJsonStr(infoDOListOfMine));
        if (CollUtil.isNotEmpty(infoDOListOfMine)) {
            throw new RuntimeException("不能再次添加自己为家庭成员");
        }

        InhabitantInfoDO infoDO = new InhabitantInfoDO();
        BeanUtil.copyProperties(reqDTo, infoDO);

        //把我自己的居住地址设置给家庭成员
        wrapper.clear();
        wrapper.eq("id", reqDTo.getInhabitantId());
        InhabitantInfoDO dbInfo = userMapper.selectOne(wrapper);
        if (dbInfo == null) {
            throw new RuntimeException("当前用户不存在");
        }
        infoDO.setResidentialId(dbInfo.getResidentialId());
        infoDO.setBuildingId(dbInfo.getBuildingId());
        infoDO.setHouseId(dbInfo.getHouseId());
        infoDO.setStreetCode(dbInfo.getStreetCode());
        infoDO.setNeighborhoodId(dbInfo.getNeighborhoodId());

        //家庭成员绑定到我自己
        infoDO.setFamilyId(reqDTo.getInhabitantId());

        String createDate = DateUtil.now();
        infoDO.setCreateDate(createDate);
        infoDO.setUpdateDate(createDate);

        infoDO.setRoleId("1");
        infoDO.setRegistered(2);
        infoDO.setSourceChannel(1);
        infoDO.setRelationId(3);
        userMapper.insert(infoDO);
        return MapUtil.of("familyInfo", infoDO);
    }

    /**
     * 根据居民表主键id查询居民信息
     *
     * @param reqDTo
     * @return
     */
    @Override
    public Map<String, Object> queryUserById(QueryUserReqDTo reqDTo) {
        Map<String, Object> map = new HashMap<>();
        InhabitantInfoDO inhabitantInfoDO = userMapper.selectById(reqDTo.getInhabitantId());
        log.info("db主键id={}查询居民信息结果：{}", reqDTo.getInhabitantId(), JSONUtil.toJsonStr(inhabitantInfoDO));
        if (inhabitantInfoDO == null) {
            return null;
        }
        //查询居委会信息
        Map<String, Object> neighborhoodMap = neighborhoodInfoMapper.selectByInhabitantId(reqDTo.getInhabitantId());
        log.info("db查询居委信息结果：{}", JSONUtil.toJsonStr(neighborhoodMap));
        inhabitantInfoDO.setOpenId("");
        map.put("inhabitantInfo", inhabitantInfoDO);
        map.put("neighborhoodInfo", neighborhoodMap);
        return map;
    }

    /**
     * 根据居委成员表主键id查询居委成员信息
     *
     * @param reqDTo
     * @return
     */
    @Override
    public Map<String, Object> queryNeighborhoodMemberById(QueryUserReqDTo reqDTo) {
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> listAllById = neighborhoodMemberMapper.listAllById(reqDTo.getNeighborhoodMemberId());
        log.info("select all member info from db id:{} ,result:{}", reqDTo.getNeighborhoodMemberId(), JSONUtil.toJsonStr(listAllById));
        //将居委会成员单独过滤成一个集合
        if (CollUtil.isEmpty(listAllById)) {
            return null;
        }
        //组装我的信息和居委的信息
        Optional<Map<String, Object>> optional = listAllById.stream().filter(mp -> reqDTo.getNeighborhoodMemberId().equals(mp.get("id"))).findAny();
        Map<String, Object> objectMap = new HashMap<>();
        optional.ifPresent(objectMap::putAll);
        map.put("id", reqDTo.getNeighborhoodMemberId());
        map.put("memberName", objectMap.get("memberName"));
        map.put("jobName", objectMap.get("jobName"));
        map.put("neighborhoodId", objectMap.get("neighborhoodId"));
        map.put("neighborhoodName", objectMap.get("neighborhoodName"));
        map.put("provinceCode", objectMap.get("provinceCode"));
        map.put("cityCode", objectMap.get("cityCode"));
        map.put("dictCode", objectMap.get("dictCode"));
        map.put("streetCode", objectMap.get("streetCode"));
        List<NeighborhoodMemberDTO> memberDTOList = listAllById
                .stream()
                .filter(mp -> !reqDTo.getNeighborhoodMemberId().equals(mp.get("id")))
                .map(m -> BeanUtil.mapToBean(m, NeighborhoodMemberDTO.class, true, CopyOptions.create()))
                .collect(Collectors.toList());
        map.put("neighborhoodMemberList", memberDTOList);
        return map;
    }

    /**
     * 根据openid查询居民信息
     *
     * @param openid
     * @return
     */
    @Override
    public Map<String, Object> queryInfoByOpenid(String openid) {
        QueryWrapper<InhabitantInfoDO> wrapper = new QueryWrapper<>();
        wrapper.eq("openId", openid);
        List<InhabitantInfoDO> infoDOs = userMapper.selectList(wrapper);
        Map<String, Object> map = new HashMap<>();
        if (infoDOs != null && infoDOs.size()!=0) {
            InhabitantInfoDO infoDO = infoDOs.get(0);
            map.put("inhabitantId", infoDO.getId());
            map.put("roleId", infoDO.getRoleId());
            map.put("registered", infoDO.getRegistered());
            map.put("sourceChannel", infoDO.getSourceChannel());
        }
        return map;
    }
}
